package jp.ac.waseda.cs.washi.game;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import jp.ac.waseda.cs.washi.gameaiarena.api.Point2;
import jp.ac.waseda.cs.washi.game.api.PumpkinType;
import jp.ac.waseda.cs.washi.game.entity.Chara;
import jp.ac.waseda.cs.washi.game.entity.Map;
import jp.ac.waseda.cs.washi.game.entity.Pumpkin;
import jp.ac.waseda.cs.washi.game.entity.PumpkinCore;
import jp.ac.waseda.cs.washi.game.entity.Tile;

final class ScoreManager {
	// ----- ----- ----- ----- fields ----- ----- ----- -----

	// ----- ----- ----- ----- methods ----- ----- ----- -----
	private ScoreManager() {
	}

	// キャラクタのスコアを更新する
	public static void updateGameScore(Map map, Chara[] charas) {
		int[] scores = { 0, 0 };
		List<Chara> charaList = Arrays.asList(charas);

		// 各タイルの所有者を判定して、所有者がいる場合にはそのキャラクタのスコアを加算する
		for (int x = 0; x < map.getWidth(); x++) {
			for (int y = 0; y < map.getHeight(); y++) {
				Tile tile = map.getTile(x, y);

				// 所有マスか魔方陣かによって得点を区別する
				Chara incompleteOwner = tile.getOwner();
				Chara owner = tile.getCompleteOwner();

				if (owner != null) {
					int charaIdx = charaList.indexOf(owner);
					scores[charaIdx] = scores[charaIdx]
							+ Settings.COMPLETE_TILE_SCORE;
				} else if (incompleteOwner != null) {
					int charaIdx = charaList.indexOf(incompleteOwner);
					scores[charaIdx] = scores[charaIdx]
							+ Settings.INCOMPLETE_TILE_SCORE;
				}
			}
		}
		// カボチャ(ボーナス図形)の探索を行う
		searchPumpkin(map, charaList, scores);

		// 各キャラクタのフィールドに、計算したスコア結果をセットする
		for (int i = 0; i < scores.length; i++) {
			charas[i].setScore(scores[i]);
		}
	}

	// 指定された地点pがボーナス図形であるかどうかを調べる
	// ボーナス図形である場合にはその所有者を返す
	// ※地点pはボーナスの中心点ではなく、ボーナス図形が収まる2次元配列の左上のマス(多分by大橋 11/05/31)
	public static Chara getPumpkinOwner(Map map, Point2 p,
			PumpkinType pumpkinType) {
		// ボーナス図形の絶対座標における最初の所有マスを計算する
		Point2 baseLocation = p.add(pumpkinType.getFirstMineLocation());
		// 指定されたマスのオーナーを取得
		Chara owner = map.getTile(baseLocation).getCompleteOwner();

		// ボーナス図形の占めるべき領域がすべて「オーナーのもの」かどうかを判定
		for (Point2 dp : pumpkinType.getOwnedLocations()) {
			Tile tile = map.getTile(p.add(dp));
			if (tile.getCompleteOwner() != owner)
				return null;
		}
		// ボーナス図形の周辺マスがすべて「オーナーのものではない」かどうかを判定
		for (Point2 dp : pumpkinType.getNotOwnedLocations()) {
			Tile tile = map.getTile(p.add(dp));
			if (tile.getCompleteOwner() == owner)
				return null;
		}
		// ここまでたどり着いた == ( ボーナス図形を形成すべきマスが埋まっている && 周囲のマスにオーナーのマスがない )
		// => 指定された地点はボーナス図形である
		return owner;
	}

	// 地点pに指定されたオーナーのカボチャがあるかどうかを判定する
	// ある場合にはそのカボチャを返す
	private static Pumpkin getPumpkin(Chara chara, Point2 p) {
		for (Pumpkin pump : chara.getPumpkins()) {
			if (pump.getLocation().equals(p)) {
				return pump;
			}
		}
		return null;
	}

	//
	public static void searchPumpkin(Map map, List<Chara> charaList,
			int[] scores) {

		// 現在のカボチャを一度すべて「破壊された状態」にする
		for (Chara chara : charaList) {
			for (Pumpkin pump : chara.getPumpkins()) {
				pump.setAlive(false);
			}
		}

		// 定義されるボーナス図形のタイプすべてについて(BIGとMINIについて：11/05/31時点)
		for (PumpkinType pumpkinType : PumpkinType.values()) {
			int h = map.getHeight() - pumpkinType.getHeight() + 1;
			int w = map.getWidth() - pumpkinType.getWidth() + 1;

			// 左上を基準としてボーナス図形がおけるタイルすべてについて
			for (Point2 p : Point2.getPoints(w, h)) {
				// 現在のマスのカボチャのオーナーを調べる
				Chara owner = getPumpkinOwner(map, p, pumpkinType);
				// ボーナスのオーナーがいた場合
				if (owner != null) {
					Pumpkin pump = getPumpkin(owner, p);
					// すでにボーナスがある場合はボーナスを活性化する
					if (pump != null) {
						pump.setAlive(true);
					}
					// まだボーナスがなかった場合は新しいカボチャを作る
					else {
						Pumpkin pumpkin = new Pumpkin(pumpkinType, p,
								Settings.PUMPKIN_STRENGTH);
						owner.getPumpkins().add(pumpkin);
					}
				}
			}
		}

		// カボチャが不活性の状態の場合はそのカボチャをキャラクタのリストから除去する
		// ※カボチャが破壊された場合or周囲のマスに魔方陣がおかれボーナス図形ではなくなった場合
		for (Chara chara : charaList) {
			ArrayList<Pumpkin> pumpkins = chara.getPumpkins();
			for (int i = pumpkins.size() - 1; i >= 0; i--) {
				if (pumpkins.get(i).isAlive() == false) {
					pumpkins.remove(i);
				}
			}
		}

		// (壁を除く)タイルのロックを初期化(すべてアンロック状態にする)
		for (Point2 p : Point2.getPoints(map.getWidth(), map.getHeight())) {
			if (map.getTile(p).getWall() == null) {
				map.getTile(p).setCanDevelop(true);
			}

		}

		// 各キャラクタのボーナス図形の位置を元にスコアを計算＆タイルのロック処理
		// TODO 処理を分割したい
		int iChara = 0;
		for (Chara chara : charaList) {
			for (Pumpkin pump : chara.getPumpkins()) {
				// １つのボーナス図形が占める領域をすべてロックする
				if (Settings.LOCKED_OPTION) {
					for (Point2 dp : pump.getType().getOwnedLocations()) {
						map.getTile(dp.add(pump.getLocation())).setCanDevelop(false);
					}
				}
				// １つのボーナス図形の中心点たちをアンロックにする（奪えるようにする）
				for (PumpkinCore core : pump.getCores()) {
					Point2 p = core.getLocation();
					map.getTile(p).setCanDevelop(true);
				}
				// map.getTile(pump.getCenterLocation()).setLock(false);
				// 当該キャラクタのスコアにボーナス１つ分のスコアを加える
				scores[iChara] += pump.getType().getScore();
			}
			// 当該キャラクタのスコアに破壊ボーナスを加える
			scores[iChara] += chara.getBreakScore() * 2;
			iChara++;
		}
	}
}
